﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using GA.Server.Api;
using System.Threading;
using System.IO;

namespace GA.Server.Configuration
{
    public class ServerElement : ConfigurationElement
    {
        [ConfigurationProperty("Name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get
            {
                return (string)this["Name"];
            }
            set
            {
                this["Name"] = value;
            }
        }

        [ConfigurationProperty("File", IsRequired = false)]
        public string File
        {
            get
            {
                return (string)this["File"];
            }
            set
            {
                this["File"] = value;
            }
        }

        [ConfigurationProperty("Assembly", IsRequired = false)]
        public string Assembly
        {
            get
            {
                return (string)this["Assembly"];
            }
            set
            {
                this["Assembly"] = value;
            }
        }

        [ConfigurationProperty("Type", IsRequired = false)]
        public string Type
        {
            get
            {
                return (string)this["Type"];
            }
            set
            {
                this["Type"] = value;
            }
        }

        [ConfigurationProperty("LoadOnStartup", IsRequired = false)]
        public bool LoadOnStartup
        {
            get
            {
                return bool.Parse(this["LoadOnStartup"].ToString());
            }
            set
            {
                this["LoadOnStartup"] = value.ToString();
            }
        }

        [ConfigurationProperty("ServerProperties", IsRequired = false, IsDefaultCollection = false)]
        public ServerPropertiesElementCollection ServerProperties
        {
            get
            {
                return (ServerPropertiesElementCollection)this["ServerProperties"];
            }
            set
            {
                this["ServerProperties"] = value;
            }
        }

        [ConfigurationProperty("StartupOrder", IsRequired = false, DefaultValue = -1)]
        public int StartupOrder
        {
            get
            {
                return int.Parse(this["StartupOrder"].ToString());
            }
            set
            {
                this["StartupOrder"] = value;
            }
        }

        [ConfigurationProperty("RequiredServers", IsRequired = false)]
        public string RequiredServers
        {
            get
            {
                return this["RequiredServers"].ToString();
            }
            set
            {
                this["RequiredServers"] = value;
            }
        }

        public GAServer GetServerInstance(bool forceLoad)
        {
            return GetServerInstance(forceLoad, ServerProperties);
        }

        public GAServer GetServerInstance(bool forceLoad, ServerPropertiesElementCollection properties)
        {
            if (Type == null || Type == string.Empty) { throw new InvalidOperationException(string.Format("Server {0} does not have a Type assocated with it.", Name)); }
            if ((File == null || File == string.Empty) && (Assembly == null || File == string.Empty)) { throw new InvalidOperationException(string.Format("Server {0} has no Assembly information.", Name)); }

            GAServer server = null;
            if (mAssembly == null || forceLoad)
            {
                if (File != null && File.Length > 0)
                {
                    FileInfo fileInfo = new FileInfo(File.StartsWith("..") ? Path.GetFullPath(File) : File);
                    if (fileInfo.Exists)
                    {
                        mAssembly = System.Reflection.Assembly.LoadFile(fileInfo.FullName);
                    }
                }
                if (Assembly != null && Assembly.Length > 0)
                {
                    mAssembly = System.Reflection.Assembly.Load(Assembly);
                }
            }
            Type type = mAssembly.GetType(Type);
            Thread thread = new Thread(() =>
            {
                server = (GAServer)type.GetConstructor(new Type[] { typeof(ServerPropertiesElementCollection) }).Invoke(new object[] { properties });
                server.Start();
            })
            {
                Name = string.Format("{0}_{1}", type.Name, DateTime.Now.ToString("MM-dd_hh-mm-ss"))
            };
            thread.Start();
            while (server == null)
            {
                Thread.Sleep(100);
            }
            server.Thread = thread;

            return server;
        }

        private System.Reflection.Assembly mAssembly = null;
    }
}
